home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / temp_buf.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-26  |  13.4 KB  |  594 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <glib.h>
  22.  
  23. #include <errno.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #ifdef HAVE_UNISTD_H
  27. #include <unistd.h>
  28. #endif
  29. #include <string.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32.  
  33. #ifdef G_OS_WIN32
  34. #include <process.h>        /* For _getpid() */
  35. #endif
  36.  
  37. #include "apptypes.h"
  38.  
  39. #include "appenv.h"
  40. #include "drawable.h"
  41. #include "gdisplay.h"
  42. #include "gimprc.h"
  43. #include "paint_funcs.h"
  44. #include "temp_buf.h"
  45.  
  46. #include "libgimp/gimpcolorspace.h"
  47.  
  48.  
  49. static guchar * temp_buf_allocate (guint);
  50. static void     temp_buf_to_color (TempBuf *, TempBuf *);
  51. static void     temp_buf_to_gray  (TempBuf *, TempBuf *);
  52.  
  53.  
  54. /*  Memory management  */
  55.  
  56. static guchar *
  57. temp_buf_allocate (guint size)
  58. {
  59.   guchar *data;
  60.  
  61.   data = g_new (guchar, size);
  62.  
  63.   return data;
  64. }
  65.  
  66.  
  67. /*  The conversion routines  */
  68.  
  69. static void
  70. temp_buf_to_color (TempBuf *src_buf, 
  71.            TempBuf *dest_buf)
  72. {
  73.   guchar *src;
  74.   guchar *dest;
  75.   long num_bytes;
  76.  
  77.   src = temp_buf_data (src_buf);
  78.   dest = temp_buf_data (dest_buf);
  79.  
  80.   num_bytes = src_buf->width * src_buf->height;
  81.  
  82.   while (num_bytes--)
  83.     {
  84.       guchar tmpch;
  85.       *dest++ = *src++;  /* alpha channel */
  86.       *dest++ = tmpch = *src++;
  87.       *dest++ = tmpch;
  88.       *dest++ = tmpch;
  89.     }
  90. }
  91.  
  92.  
  93. static void
  94. temp_buf_to_gray (TempBuf *src_buf, 
  95.           TempBuf *dest_buf)
  96. {
  97.   guchar *src;
  98.   guchar *dest;
  99.   long  num_bytes;
  100.   float pix;
  101.  
  102.   src = temp_buf_data (src_buf);
  103.   dest = temp_buf_data (dest_buf);
  104.  
  105.   num_bytes = src_buf->width * src_buf->height;
  106.  
  107.   while (num_bytes--)
  108.     {
  109.       *dest++ = src[0];  /* alpha channel */
  110.  
  111.       pix = INTENSITY (src[1], src[2], src[3]);
  112.       *dest++ = (guchar) pix;
  113.  
  114.       src += 4;
  115.     }
  116. }
  117.  
  118.  
  119. TempBuf *
  120. temp_buf_new (gint    width, 
  121.           gint    height, 
  122.           gint    bytes, 
  123.           gint    x, 
  124.           gint    y, 
  125.           guchar *col)
  126. {
  127.   long i;
  128.   int  j;
  129.   guchar  *data;
  130.   TempBuf *temp;
  131.  
  132.   temp = g_new (TempBuf, 1);
  133.  
  134.   temp->width  = width;
  135.   temp->height = height;
  136.   temp->bytes  = bytes;
  137.   temp->x      = x;
  138.   temp->y      = y;
  139.   temp->swapped = FALSE;
  140.   temp->filename = NULL;
  141.  
  142.   temp->data = data = temp_buf_allocate (width * height * bytes);
  143.  
  144.   /*  initialize the data  */
  145.   if (col)
  146.     {
  147.       /* First check if we can save a lot of work */
  148.       if (bytes == 1)
  149.         {
  150.           memset (data, *col, width * height);
  151.         }
  152.       else if ((bytes == 3) && (col[1] == *col) && (*col == col[2]))
  153.         {
  154.           memset (data, *col, width * height * 3);
  155.         }
  156.       else if ((bytes == 4) && (col[1] == *col) && (*col == col[2]) && (col[2] == col[3]))
  157.         {
  158.           memset (data, *col, (width * height) << 2);
  159.         }
  160.       else
  161.         {
  162.           /* No, we cannot */
  163.           guchar * dptr;
  164.           /* Fill the first row */
  165.           dptr = data;
  166.           for (i = width - 1; i >= 0; --i)
  167.             {
  168.               guchar * init;
  169.               j = bytes;
  170.               init = col;
  171.               while (j--)
  172.                 *dptr++ = *init++;
  173.             }
  174.           /* Now copy from it (we set bytes to bytesperrow now) */
  175.           bytes *= width;
  176.           while (--height)
  177.             {
  178.               memcpy (dptr, data, bytes);
  179.               dptr += bytes;
  180.             }
  181.         }
  182.     }
  183.  
  184.   return temp;
  185. }
  186.  
  187.  
  188. TempBuf *
  189. temp_buf_copy (TempBuf *src, 
  190.            TempBuf *dest)
  191. {
  192.   TempBuf * new;
  193.   long length;
  194.  
  195.   if (!src)
  196.     {
  197.       g_message ("trying to copy a temp buf which is NULL.");
  198.       return dest;
  199.     }
  200.  
  201.   if (!dest)
  202.     new = temp_buf_new (src->width, src->height, src->bytes, 0, 0, NULL);
  203.   else
  204.     {
  205.       new = dest;
  206.       if (dest->width != src->width || dest->height != src->height)
  207.     g_message ("In temp_buf_copy, the widths or heights don't match.");
  208.       /*  The temp buf is smart, and can translate between color and gray  */
  209.       /*  (only necessary if not we allocated it */
  210.       if (src->bytes != new->bytes)
  211.         {
  212.           if (src->bytes == 4)  /* RGB color */
  213.         temp_buf_to_gray (src, new);
  214.           else if (src->bytes == 2) /* grayscale */
  215.         temp_buf_to_color (src, new);
  216.           else
  217.         g_message ("Cannot convert from indexed color.");
  218.       return new;
  219.         }
  220.     }
  221.  
  222.   /* make the copy */
  223.   length = src->width * src->height * src->bytes;
  224.   memcpy (temp_buf_data (new), temp_buf_data (src), length);
  225.  
  226.   return new;
  227. }
  228.  
  229.  
  230. TempBuf *
  231. temp_buf_resize (TempBuf *buf, 
  232.          gint     bytes, 
  233.          gint     x, 
  234.          gint     y, 
  235.          gint     w, 
  236.          gint     h)
  237. {
  238.   gint size;
  239.  
  240.   /*  calculate the requested size  */
  241.   size = w * h * bytes;
  242.  
  243.   /*  First, configure the canvas buffer  */
  244.   if (!buf)
  245.     buf = temp_buf_new (w, h, bytes, x, y, NULL);
  246.   else
  247.     {
  248.       if (size != (buf->width * buf->height * buf->bytes))
  249.       {
  250.     /*  Make sure the temp buf is unswapped  */
  251.     temp_buf_unswap (buf);
  252.  
  253.     /*  Reallocate the data for it  */
  254.     buf->data = g_realloc (buf->data, size);
  255.       }
  256.  
  257.       /*  Make sure the temp buf fields are valid  */
  258.       buf->x = x;
  259.       buf->y = y;
  260.       buf->width = w;
  261.       buf->height = h;
  262.       buf->bytes = bytes;
  263.     }
  264.  
  265.   return buf;
  266. }
  267.  
  268.  
  269. TempBuf *
  270. temp_buf_copy_area (TempBuf *src, 
  271.             TempBuf *dest, 
  272.             gint     x, 
  273.             gint     y, 
  274.             gint     w, 
  275.             gint     h, 
  276.             gint     border)
  277. {
  278.   TempBuf * new;
  279.   PixelRegion srcR, destR;
  280.   guchar empty[MAX_CHANNELS] = { 0, 0, 0, 0 };
  281.   gint x1, y1, x2, y2;
  282.  
  283.   if (!src)
  284.     {
  285.       g_message ("trying to copy a temp buf which is NULL.");
  286.       return dest;
  287.     }
  288.  
  289.   /*  some bounds checking  */
  290.   x1 = CLAMP (x, 0, src->width);
  291.   y1 = CLAMP (y, 0, src->height);
  292.   x2 = CLAMP (x + w, 0, src->width);
  293.   y2 = CLAMP (y + h, 0, src->height);
  294.  
  295.   if (!(x2 - x1) || !(y2 - y1))
  296.     return dest;
  297.  
  298.   x = x1 - border;
  299.   y = y1 - border;
  300.   w = (x2 - x1) + border * 2;
  301.   h = (y2 - y1) + border * 2;
  302.  
  303.   if (!dest)
  304.     new = temp_buf_new (w, h, src->bytes, x, y, empty);
  305.   else
  306.     {
  307.       new = dest;
  308.       if (dest->bytes != src->bytes)
  309.     g_message ("In temp_buf_copy_area, the widths or heights or bytes don't match.");
  310.     }
  311.  
  312.   /*  Set the offsets for the dest  */
  313.   new->x = src->x + x;
  314.   new->y = src->y + y;
  315.  
  316.   /*  Copy the region  */
  317.   srcR.bytes = src->bytes;
  318.   srcR.w = (x2 - x1);
  319.   srcR.h = (y2 - y1);
  320.   srcR.rowstride = src->bytes * src->width;
  321.   srcR.data = temp_buf_data (src) + y1 * srcR.rowstride + x1 * srcR.bytes;
  322.  
  323.   destR.rowstride = new->bytes * new->width;
  324.   destR.data = temp_buf_data (new) + (y1 - y) * destR.rowstride + (x1 - x) * srcR.bytes;
  325.  
  326.   copy_region (&srcR, &destR);
  327.  
  328.   return new;
  329. }
  330.  
  331.  
  332. void
  333. temp_buf_free (TempBuf *temp_buf)
  334. {
  335.   if (temp_buf->data)
  336.     g_free (temp_buf->data);
  337.  
  338.   if (temp_buf->swapped)
  339.     temp_buf_swap_free (temp_buf);
  340.  
  341.   g_free (temp_buf);
  342. }
  343.  
  344.  
  345. guchar *
  346. temp_buf_data (TempBuf *temp_buf)
  347. {
  348.   if (temp_buf->swapped)
  349.     temp_buf_unswap (temp_buf);
  350.  
  351.   return temp_buf->data;
  352. }
  353.  
  354.  
  355. /******************************************************************
  356.  *  Mask buffer functions                                         *
  357.  ******************************************************************/
  358.  
  359.  
  360. MaskBuf *
  361. mask_buf_new (gint width, 
  362.           gint height)
  363. {
  364.   static guchar empty = 0;
  365.  
  366.   return (temp_buf_new (width, height, 1, 0, 0, &empty));
  367. }
  368.  
  369.  
  370. void
  371. mask_buf_free (MaskBuf *mask)
  372. {
  373.   temp_buf_free ((TempBuf *) mask);
  374. }
  375.  
  376.  
  377. guchar *
  378. mask_buf_data (MaskBuf *mask_buf)
  379. {
  380.   if (mask_buf->swapped)
  381.     temp_buf_unswap (mask_buf);
  382.  
  383.   return mask_buf->data;
  384. }
  385.  
  386.  
  387. /******************************************************************
  388.  *  temp buffer disk caching functions                            *
  389.  ******************************************************************/
  390.  
  391. /*  NOTES:
  392.  *  Disk caching is setup as follows:
  393.  *    On a call to temp_buf_swap, the TempBuf parameter is stored
  394.  *    in a temporary variable called cached_in_memory.
  395.  *    On the next call to temp_buf_swap, if cached_in_memory is non-null,
  396.  *    cached_in_memory is moved to disk, and the latest TempBuf parameter
  397.  *    is stored in cached_in_memory.  This method keeps the latest TempBuf
  398.  *    structure in memory instead of moving it directly to disk as requested.
  399.  *    On a call to temp_buf_unswap, if cached_in_memory is non-null, it is
  400.  *    compared against the requested TempBuf.  If they are the same, nothing
  401.  *    must be moved in from disk since it still resides in memory.  However,
  402.  *    if the two pointers are different, the requested TempBuf is retrieved
  403.  *    from disk.  In the former case, cached_in_memory is set to NULL;
  404.  *    in the latter case, cached_in_memory is left unchanged.
  405.  *    If temp_buf_swap_free is called, cached_in_memory must be checked
  406.  *    against the temp buf being freed.  If they are the same, then 
  407.  *    cached_in_memory must be set to NULL;
  408.  *
  409.  *  In the case where memory usage is set to "stingy":
  410.  *    temp bufs are not cached in memory at all, they go right to disk.
  411.  */
  412.  
  413.  
  414. /*  a static counter for generating unique filenames  */
  415. static gint swap_index = 0;
  416.  
  417. /*  a static pointer which keeps track of the last request for a swapped buffer  */
  418. static TempBuf * cached_in_memory = NULL;
  419.  
  420.  
  421. static gchar *
  422. generate_unique_filename (void)
  423. {
  424.   pid_t pid;
  425.   pid = getpid ();
  426.   return g_strdup_printf ("%s" G_DIR_SEPARATOR_S "gimp%d.%d",
  427.               temp_path, (int) pid, swap_index++);
  428. }
  429.  
  430.  
  431. void
  432. temp_buf_swap (TempBuf *buf)
  433. {
  434.   TempBuf * swap;
  435.   gchar * filename;
  436.   struct stat stat_buf;
  437.   gint err;
  438.   FILE * fp;
  439.  
  440.   if (!buf || buf->swapped)
  441.     return;
  442.  
  443.   /*  Set the swapped flag  */
  444.   buf->swapped = TRUE;
  445.  
  446.   if (stingy_memory_use)
  447.     swap = buf;
  448.   else
  449.     {
  450.       swap = cached_in_memory;
  451.       cached_in_memory = buf;
  452.     }
  453.  
  454.   /*  For the case where there is no temp buf ready to be moved to disk, return  */
  455.   if (!swap)
  456.     return;
  457.  
  458.   /*  Get a unique filename for caching the data to a UNIX file  */
  459.   filename = generate_unique_filename ();
  460.  
  461.   /*  Check if generated filename is valid  */
  462.   err = stat (filename, &stat_buf);
  463.   if (!err)
  464.     {
  465.       if (stat_buf.st_mode & S_IFDIR)
  466.     {
  467.       g_message ("Error in temp buf caching: \"%s\" is a directory (cannot overwrite)", filename);
  468.       g_free (filename);
  469.       return;
  470.     }
  471.     }
  472.  
  473.   /*  Open file for overwrite  */
  474.   if ((fp = fopen (filename, "wb")))
  475.     {
  476.       size_t blocks_written;
  477.       blocks_written = fwrite (swap->data, swap->width * swap->height * swap->bytes, 1, fp);
  478.       /* Check whether all bytes were written and fclose() was able to flush its buffers */
  479.       if ((0 != fclose (fp)) || (1 != blocks_written))
  480.         {
  481.           (void) unlink (filename);
  482.           perror ("Write error on temp buf");
  483.           g_message ("Cannot write \"%s\"", filename);
  484.           g_free (filename);
  485.           return;
  486.         }
  487.     }
  488.   else
  489.     {
  490.       (void) unlink (filename);
  491.       perror ("Error in temp buf caching");
  492.       g_message ("Cannot write \"%s\"", filename);
  493.       g_free (filename);
  494.       return;
  495.     }
  496.   /*  Finally, free the buffer's data  */
  497.   g_free (swap->data);
  498.   swap->data = NULL;
  499.  
  500.   swap->filename = filename;
  501. }
  502.  
  503.  
  504. void
  505. temp_buf_unswap (TempBuf *buf)
  506. {
  507.   struct stat stat_buf;
  508.   FILE * fp;
  509.   gboolean succ = FALSE;
  510.  
  511.   if (!buf || !buf->swapped)
  512.     return;
  513.  
  514.   /*  Set the swapped flag  */
  515.   buf->swapped = FALSE;
  516.  
  517.   /*  If the requested temp buf is still in memory, simply return  */
  518.   if (cached_in_memory == buf)
  519.     {
  520.       cached_in_memory = NULL;
  521.       return;
  522.     }
  523.  
  524.   /*  Allocate memory for the buffer's data  */
  525.   buf->data   = temp_buf_allocate (buf->width * buf->height * buf->bytes);
  526.  
  527.   /*  Find out if the filename of the swapped data is an existing file... */
  528.   /*  (buf->filname HAS to be != 0 */
  529.   if (!stat (buf->filename, &stat_buf))
  530.     {
  531.       if ((fp = fopen (buf->filename, "rb")))
  532.     {
  533.       size_t blocks_read;
  534.       blocks_read = fread (buf->data, buf->width * buf->height * buf->bytes, 1, fp);
  535.       (void) fclose (fp);
  536.       if (blocks_read != 1)
  537.             perror ("Read error on temp buf");
  538.       else
  539.         succ = TRUE;
  540.     }
  541.       else
  542.     perror ("Error in temp buf caching");
  543.  
  544.       /*  Delete the swap file  */
  545.       unlink (buf->filename);
  546.     }
  547.   if (!succ)
  548.     g_message ("Error in temp buf caching: information swapped to disk was lost!");
  549.  
  550.   g_free (buf->filename);   /*  free filename  */
  551.   buf->filename = NULL;
  552. }
  553.  
  554.  
  555. void
  556. temp_buf_swap_free (TempBuf *buf)
  557. {
  558.   struct stat stat_buf;
  559.  
  560.   if (!buf->swapped)
  561.     return;
  562.  
  563.   /*  Set the swapped flag  */
  564.   buf->swapped = FALSE;
  565.  
  566.   /*  If the requested temp buf is cached in memory...  */
  567.   if (cached_in_memory == buf)
  568.     {
  569.       cached_in_memory = NULL;
  570.       return;
  571.     }
  572.  
  573.   /*  Find out if the filename of the swapped data is an existing file... */
  574.   if (!stat (buf->filename, &stat_buf))
  575.     {
  576.       /*  Delete the swap file  */
  577.       unlink (buf->filename);
  578.     }
  579.   else
  580.     g_message ("Error in temp buf disk swapping: information swapped to disk was lost!");
  581.  
  582.   if (buf->filename)
  583.     g_free (buf->filename);   /*  free filename  */
  584.   buf->filename = NULL;
  585. }
  586.  
  587.  
  588. void
  589. swapping_free (void)
  590. {
  591.   if (cached_in_memory)
  592.     temp_buf_free (cached_in_memory);
  593. }
  594.